package com.beyondsoft.mcms.web;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.PersistenceException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.roo.addon.web.mvc.controller.finder.RooWebFinder;
import org.springframework.roo.addon.web.mvc.controller.scaffold.RooWebScaffold;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.beyondsoft.mcms.common.CommonUtils;
import com.beyondsoft.mcms.common.Constants;
import com.beyondsoft.mcms.common.I18NUtils;
import com.beyondsoft.mcms.domain.Advice;
import com.beyondsoft.mcms.domain.Attendee;
import com.beyondsoft.mcms.domain.Category;
import com.beyondsoft.mcms.domain.Conference;
import com.beyondsoft.mcms.domain.Item;
import com.beyondsoft.mcms.domain.MemberInfo;
import com.beyondsoft.mcms.reference.AuthRole;
import com.beyondsoft.mcms.service.AttendeeService;
import com.beyondsoft.mcms.service.ConferenceService;
import com.beyondsoft.mcms.service.MemberInfoService;
import flexjson.JSONSerializer;

@RequestMapping("/attendees")
@Controller
@RooWebScaffold(path = "attendees", formBackingObject = Attendee.class)
@RooWebFinder
public class AttendeeController {

    @Autowired
    MemberInfoService memberInfoService;

    @Autowired
    ConferenceService conferenceService;

    @Autowired
    AttendeeService attendeeService;

    @RequestMapping(params = "form", produces = "text/html")
    public String createForm(Model uiModel) {
        Attendee attendee = new Attendee();
        attendee.setCreateDate(new Date());
        attendee.setCreatedBy(CommonUtils.getCurrentUsername());
        attendee.setAttendStatus(Item.findItem(Constants.ATTENDEE_STATUS_REGISTERED));
        populateEditForm(uiModel, attendee);
        return "attendees/create";
    }

    @RequestMapping(method = RequestMethod.POST, produces = "application/json")
    public void create(Attendee attendee, BindingResult bindingResult, HttpServletRequest httpServletRequest, HttpServletResponse response) {
        Map<String, Object> validResult = new HashMap<String, Object>();
        if (Attendee.countAttendes(attendee.getConference(), null) >= attendee.getConference().getMaxEntries()) {
            validResult.put(Constants.ERROR_CODE, "conference_field_attendee_full");
            validResult.put(Constants.ERROR_MSG, I18NUtils.getMessage("conference_field_attendee_full"));
        } else {
            attendee.setAttendName(attendee.getAttendName().trim());
            attendee.setCreateDate(new Date());
            List<Attendee> existed = Attendee.findAttendeesByConferenceAndMemberInfoAndAttendNameEquals(attendee.getConference(), attendee.getMemberInfo(), attendee.getAttendName()).getResultList();
            if (existed != null && existed.size() > 0) {
                validResult.put(Constants.ERROR_CODE, "attendee_field_attendName_existed");
                validResult.put(Constants.ERROR_MSG, I18NUtils.getMessage("attendee_field_attendName_existed", attendee.getAttendName(), attendee.getConference().getName()));
            } else {
                attendee.persist();
                validResult.put(Constants.CREATE_SUCCESS_CODE, Constants.CREATE_SUCCESS_MSG);
            }
        }
        String reponseStr = new JSONSerializer().exclude("*.class").serialize(validResult);
        try {
            response.getWriter().write(reponseStr);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @RequestMapping(value = "/{id}", params = "form", produces = "text/html")
    public String updateForm(@PathVariable("id") Long id, Model uiModel) {
        Attendee attendee = Attendee.findAttendee(id);
        attendee.setUpdateDate(new Date());
        attendee.setUpdatedBy(SecurityContextHolder.getContext().getAuthentication().getName());
        populateEditForm(uiModel, attendee);
        return "attendees/update";
    }

    @RequestMapping(method = RequestMethod.PUT, produces = "text/html")
    public String update(@Valid Attendee attendee, @RequestParam("conference.id") Conference conference, @RequestParam("memberInfo.id") MemberInfo memberInfo, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
        if (bindingResult.hasErrors()) {
            populateEditForm(uiModel, attendee);
            return "attendees/update";
        }
        uiModel.asMap().clear();
        attendee.setConference(conference);
        attendee.setMemberInfo(memberInfo);
        attendee.merge();
        return "redirect:/attendees/" + encodeUrlPathSegment(attendee.getId().toString(), httpServletRequest);
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE, produces = "text/html")
    public String delete(@PathVariable("id") Long id, @RequestParam(value = "page", required = false) Integer page, @RequestParam(value = "size", required = false) Integer size, Model uiModel) {
        Attendee attendee = Attendee.findAttendee(id);
        String username = SecurityContextHolder.getContext().getAuthentication().getName();
        AuthRole authority = CommonUtils.getCurrentRole();
        if (username.equals(attendee.getCreatedBy()) || authority.equals(AuthRole.ADMIN)) {
            attendee.remove();
            uiModel.asMap().clear();
            uiModel.addAttribute("page", (page == null) ? "1" : page.toString());
            uiModel.addAttribute("size", (size == null) ? "10" : size.toString());
            return "redirect:/attendees";
        } else {
            return "dataAccessFailure";
        }
    }

    @RequestMapping(value = "/{id}", produces = "text/html")
    public String show(@PathVariable("id") Long id, Model uiModel) {
        addDateTimeFormatPatterns(uiModel);
        uiModel.addAttribute("attendee", Attendee.findAttendee(id));
        uiModel.addAttribute("itemId", id);
        return "attendees/show";
    }

    void addDateTimeFormatPatterns(Model uiModel) {
        uiModel.addAttribute("attendee_createdate_date_format", DateTimeFormat.patternForStyle("M-", LocaleContextHolder.getLocale()));
        uiModel.addAttribute("attendee_updatedate_date_format", DateTimeFormat.patternForStyle("M-", LocaleContextHolder.getLocale()));
    }

    void populateEditForm(Model uiModel, Attendee attendee) {
        uiModel.addAttribute("attendee", attendee);
        addDateTimeFormatPatterns(uiModel);
        List<Conference> conferences = new ArrayList<Conference>();
        List<MemberInfo> memberinfoes = new ArrayList<MemberInfo>();
        List<Item> attendstatuses = new ArrayList<Item>();
        AuthRole authority = CommonUtils.getCurrentRole();
        if (authority.equals(AuthRole.ADMIN)) {
            conferences = Advice.findConferencesByMemberInfoAndConferenceStatus(null, Item.findItem(Constants.CONFERENCE_STATUS_REGISTERING)).getResultList();
            if (conferences != null && !conferences.isEmpty()) memberinfoes = MemberInfo.findMemberInfoesByConference(conferences.get(0).getId()).getResultList();
            attendstatuses = Item.findItemsByCategoryAndIsValid(Category.findCategory(Constants.ATTENDEE_STATUS), true).getResultList();
        } else {
            conferences = Advice.findConferencesByMemberInfoAndConferenceStatus(CommonUtils.getCurrentMember(), Item.findItem(Constants.CONFERENCE_STATUS_REGISTERING)).getResultList();
            memberinfoes.add(CommonUtils.getCurrentMember());
            attendstatuses.add(Item.findItem(Constants.ATTENDEE_STATUS_REGISTERED));
        }
        uiModel.addAttribute("conferences", CommonUtils.convertToNoRepeatedList(conferences));
        uiModel.addAttribute("memberinfoes", memberinfoes);
        uiModel.addAttribute("attendstatuses", attendstatuses);
        List<String[]> dependencies = new ArrayList<String[]>();
        if (conferences.size() == 0) {
            dependencies.add(new String[] { "conference", "conferences" });
        }
        uiModel.addAttribute("dependencies", dependencies);
    }

    @RequestMapping(params = { "smsIds", "sms" }, method = RequestMethod.GET)
    public String smsSending(Model uiModel, HttpServletRequest request) {
        String ids = request.getParameter("smsIds");
        String sms = request.getParameter("sms");
        if (ids != null && ids.length() > 0) {
            if (ids.endsWith(",")) {
                ids = ids.substring(0, ids.length() - 1);
            }
            attendeeService.smSending(ids, sms);
        }
        return list(1, 10, uiModel);
    }

    @RequestMapping(params = "signIds", method = RequestMethod.GET)
    public String batchSigning(Model uiModel, HttpServletRequest request) {
        String ids = request.getParameter("signIds");
        if (ids != null && ids.length() > 0) {
            if (ids.endsWith(",")) {
                ids = ids.substring(0, ids.length() - 1);
            }
            attendeeService.batchSigning(ids.split(","));
        }
        return list(1, 10, uiModel);
    }

    @RequestMapping(params = { "find=ByConferenceAndMemberInfo", "form" }, method = RequestMethod.GET)
    public String findAttendeesByConferenceAndMemberInfoForm(Model uiModel) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        request.getSession().setAttribute("memberInfo", null);
        request.getSession().setAttribute("conference", null);
        return findAttendeesByConferenceAndMemberInfo(null, null, uiModel);
    }

    @RequestMapping(params = "find=ByConferenceAndMemberInfo", method = RequestMethod.GET)
    public String findAttendeesByConferenceAndMemberInfo(@RequestParam(value = "memberInfo", required = false) MemberInfo memberInfo, @RequestParam(value = "conference", required = false) Conference conference, Model uiModel) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String page = request.getParameter("page");
        String size = request.getParameter("size");
        int sizeNo = size == null ? 10 : Integer.valueOf(size);
        int pageNo = page == null ? 1 : Integer.valueOf(page);
        if (page != null && size != null) {
            conference = (Conference) request.getSession().getAttribute("conference");
            memberInfo = (MemberInfo) request.getSession().getAttribute("memberInfo");
        } else {
            request.getSession().setAttribute("conference", conference);
            request.getSession().setAttribute("memberInfo", memberInfo);
        }
        uiModel.addAttribute("conference", conference);
        uiModel.addAttribute("memberInfo", memberInfo);
        return list(pageNo, sizeNo, uiModel);
    }

    @RequestMapping(produces = "text/html")
    public String list(@RequestParam(value = "page", required = false) Integer page, @RequestParam(value = "size", required = false) Integer size, Model uiModel) {
        List<Conference> conferences = new ArrayList<Conference>();
        List<MemberInfo> memberinfoes = new ArrayList<MemberInfo>();
        AuthRole authority = CommonUtils.getCurrentRole();
        if (authority.equals(AuthRole.ADMIN)) {
            conferences = Advice.findConferencesByMemberInfoAndConferenceStatus(null, null).getResultList();
            memberinfoes = MemberInfo.findAllMemberInfoes();
        } else {
            conferences = Advice.findConferencesByMemberInfoAndConferenceStatus(CommonUtils.getCurrentMember(), Item.findItem(Constants.CONFERENCE_STATUS_REGISTERING)).getResultList();
            memberinfoes.add(CommonUtils.getCurrentMember());
        }
        uiModel.addAttribute("conferences", CommonUtils.convertToNoRepeatedList(conferences));
        uiModel.addAttribute("memberinfoes", memberinfoes);
        Conference conference = (Conference) uiModel.asMap().get("conference");
        MemberInfo memberInfo = (MemberInfo) uiModel.asMap().get("memberInfo");
        int sizeNo = size == null ? 10 : size.intValue();
        final int firstResult = page == null ? 0 : (page.intValue() - 1) * sizeNo;
        float nrOfPages = 0.0f;
        List<Attendee> attendees = new ArrayList<Attendee>();
        if (authority.equals(AuthRole.ADMIN)) {
            attendees = Attendee.findAttendeesByConferenceAndMemberInfo(memberInfo, conference).getResultList();
        } else {
            if (conference == null && conferences == null && conferences.isEmpty()) {
                attendees = new ArrayList<Attendee>();
            } else {
                if (conference == null) {
                    attendees = Attendee.findAttendeesByConferencesAndMemberInfo(CommonUtils.getCurrentMember(), conferences.toArray(new Conference[] {  })).getResultList();
                } else {
                    attendees = Attendee.findAttendeesByConferenceAndMemberInfo(CommonUtils.getCurrentMember(), conference).getResultList();
                }
                filterAttendees(attendees);
            }
        }
        int lastResult = (attendees.size() > (sizeNo + firstResult)) ? (sizeNo + firstResult) : attendees.size();
        nrOfPages = (float) attendees.size() / sizeNo;
        uiModel.addAttribute("maxPages", (int) ((nrOfPages > (int) nrOfPages || nrOfPages == 0.0) ? nrOfPages + 1 : nrOfPages));
        uiModel.addAttribute("attendees", attendees.subList(firstResult, lastResult));
        uiModel.addAttribute("find", "ByConferenceAndMemberInfo");
        uiModel.addAttribute("selectQueryIds", (conference == null ? "-1" : conference.getId()) + "," + (memberInfo == null ? "-1" : memberInfo.getId()));
        addDateTimeFormatPatterns(uiModel);
        if (authority.equals(AuthRole.ORDINARY)) {
            return "attendees/ordinarylist";
        } else {
            if (conference == null) {
                uiModel.addAttribute("signFlag", "disabled");
                return "attendees/list";
            }
            Long conferenceStatus = conference.getConferenceStatus().getId();
            if (conferenceStatus <= Constants.CONFERENCE_STATUS_REGISTERING) {
                uiModel.addAttribute("signFlag", "disabled");
            }
            return "attendees/list";
        }
    }

    @RequestMapping(value = "list/{id}", produces = "text/html")
    public String listByAdvice(@PathVariable("id") Long id, Model uiModel) {
        List<Attendee> attendees = new ArrayList<Attendee>();
        List<Conference> conferences = new ArrayList<Conference>();
        List<Item> attendstatuses = new ArrayList<Item>();
        AuthRole authority = CommonUtils.getCurrentRole();
        if (authority.equals(AuthRole.ADMIN)) {
            Advice advice = Advice.findAdvice(id);
            attendees = Attendee.findAttendeesByConferenceAndMemberInfo(advice.getMemberInfo(), advice.getConference()).getResultList();
            uiModel.addAttribute("attendees", attendees);
            uiModel.addAttribute("memberInfo", advice.getMemberInfo());
            uiModel.addAttribute("conference", advice.getConference());
            attendstatuses = Item.findItemsByCategoryAndIsValid(Category.findCategory(Constants.ATTENDEE_STATUS), true).getResultList();
            uiModel.addAttribute("attendstatuses", attendstatuses);
            uiModel.addAttribute("statusids", getAttendeeStatuses(attendees));
            return "attendees/batchedit";
        } else {
            conferences = Advice.findConferencesByMemberInfoAndConferenceStatus(CommonUtils.getCurrentMember(), Item.findItem(Constants.CONFERENCE_STATUS_REGISTERING)).getResultList();
            uiModel.addAttribute("memberInfo", CommonUtils.getCurrentMember());
            uiModel.addAttribute("conferences", CommonUtils.convertToNoRepeatedList(conferences));
            uiModel.addAttribute("attendstatus", Item.findItem(Constants.ATTENDEE_STATUS_REGISTERED));
            return "attendees/batchadd";
        }
    }

    @RequestMapping(value = "batchsave", produces = "text/html")
    public String batchupdate(Model uiModel, HttpServletRequest request) {
        String[] conferences = request.getParameterValues("conference");
        String[] memberinfoes = request.getParameterValues("memberInfo");
        String[] attendeeNames = request.getParameterValues("attendeeName");
        String[] attendeeMobiles = request.getParameterValues("attendeeMobile");
        String[] attendeeStatuses = request.getParameterValues("attendeeStatus");
        List<Attendee> attendees = new ArrayList<Attendee>();
        for (int i = conferences.length - 1; i > 0; i--) {
            Attendee attendee = new Attendee();
            attendee.setConference(Conference.findConference(Long.valueOf(conferences[i])));
            attendee.setMemberInfo(MemberInfo.findMemberInfo(Long.valueOf(memberinfoes[i])));
            attendee.setAttendName(attendeeNames[i].trim());
            attendee.setAttendMobilePhone(attendeeMobiles[i].trim());
            attendee.setAttendStatus(Item.findItem(Long.valueOf(attendeeStatuses[i])));
            attendee.setCreateDate(new Date());
            attendee.setCreatedBy(CommonUtils.getCurrentUsername());
            attendees.add(attendee);
        }
        AuthRole authority = CommonUtils.getCurrentRole();
        if (authority.equals(AuthRole.ADMIN)) {
            Conference conference = Conference.findConference(Long.valueOf(conferences[0]));
            MemberInfo memberInfo = MemberInfo.findMemberInfo(Long.valueOf(memberinfoes[0]));
            Advice advice = Advice.findAdvicesByConferenceAndMemberInfo(conference, memberInfo).getSingleResult();
            attendeeService.saveAttendees(advice, convertToNoRepeatedList(attendees));
            return "redirect:/attendees/list/" + encodeUrlPathSegment(advice.getId().toString(), request);
        } else {
            try {
                attendeeService.saveAttendees(null, convertToNoRepeatedList(attendees));
            } catch (Exception e) {
                uiModel.addAttribute("error_msg_code", e.getMessage());
                return listByAdvice(0L, uiModel);
            }
            return "redirect:/attendees?find=ByConferenceAndMemberInfo";
        }
    }

    private List<Attendee> convertToNoRepeatedList(List<Attendee> objects) {
        List<Attendee> results = new ArrayList<Attendee>();
        for (int i = 0; i < objects.size(); i++) {
            Attendee obj = objects.get(i);
            if (obj.getCreateDate().after(obj.getConference().getRegistrationEndTime())) {
                throw new PersistenceException("conference_field_attendee_date");
            }
            for (int j = i + 1; j < objects.size(); j++) {
                Attendee reobj = objects.get(j);
                if (obj.getConference().equals(reobj.getConference()) && obj.getMemberInfo().equals(reobj.getMemberInfo()) && obj.getAttendName().equals(reobj.getAttendName())) {
                    objects.remove(reobj);
                    j--;
                }
            }
            results.add(obj);
        }
        return results;
    }

    private String getAttendeeStatuses(List<Attendee> attendees) {
        String result = "";
        for (int i = 0; i < attendees.size(); i++) {
            result += "," + attendees.get(i).getAttendStatus().getId();
        }
        return result;
    }

    private void filterAttendees(List<Attendee> attendees) {
        for (int i = attendees.size() - 1; i >= 0; i--) {
            Attendee attendee = attendees.get(i);
            if (attendee.getConference().getConferenceStatus().getId() != Constants.CONFERENCE_STATUS_REGISTERING) {
                attendees.remove(attendee);
            }
        }
    }

    @RequestMapping(params = { "find=ByConferenceAndMemberInfo", "exportFlag=true" }, produces = "application/vnd.ms-excel", method = RequestMethod.GET)
    public String exportAttendeesByConferenceAndMemberInfo(@RequestParam(value = "conference", required = false) Conference conference, @RequestParam(value = "memberInfo", required = false) MemberInfo memberInfo, HttpServletRequest request, HttpServletResponse response, Model uiModel) {
        List<Attendee> attendees = Attendee.findAttendeesByConferenceAndMemberInfo(memberInfo, conference).getResultList();
        uiModel.addAttribute("conference", conference);
        uiModel.addAttribute("attendees", attendees);
        response.setHeader("Content-Disposition", "attachment;filename=" + encodeUrlPathSegment("签到表", request) + ".xls");
        return "attendees/exportExcel";
    }
}
